package com.katze.common.http;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * 说  明：初始化http/https请求基础对象与参数
 * 作  者：zf.zeng
 * 日  期：2020-11-30 (星期一)
 **/
public abstract class BaseRequester implements SendRequest {

    public static final String HEADER_DATE = "Date";

    private URLConnection connection = null;
    private String uri;
    private String params;
    private int timeOut = 5000;
    private final Map<String, String> headers = new ConcurrentHashMap<>();

    private URLConnection initConnection() throws IOException {
        URLConnection connection = new URL(this.uri).openConnection();
        connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        connection.setRequestProperty("Accept", "*/*");
        connection.setRequestProperty("Accept-Charset", "UTF-8");
        connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty(HEADER_DATE, String.valueOf(System.currentTimeMillis()));
        headers.forEach(connection::addRequestProperty);
        if(this.timeOut != 0) connection.setConnectTimeout(this.timeOut);// 设置一个指定的超时值（以毫秒为单位）
//        connection.setReadTimeout(5000);  // 读取数据时长，目标地址内部处理业务时长
        return connection;
    }

    private HttpURLConnection initHttpURL(RequestMethod method) throws IOException {
        this.connection = this.initConnection();
        HttpURLConnection httpURLConnection = (HttpURLConnection) this.connection;
        initMethod(httpURLConnection, method);
        return httpURLConnection;
    }

    private HttpURLConnection initHttpsURL(RequestMethod method) throws IOException {
        this.connection = this.initConnection();
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) this.connection;
        this.initSSL(httpsURLConnection);
        initMethod(httpsURLConnection, method);
        return httpsURLConnection;
    }

    protected HttpURLConnection getConnection(RequestMethod method) throws IOException {
        return this.uri.startsWith("https")? this.initHttpsURL(method):this.initHttpURL(method);
    }

    protected void initMethod(HttpURLConnection httpURLConnection, RequestMethod method) throws IOException {
        switch (method){
            case DELETE:
            case GET:
                httpURLConnection.setRequestMethod(method.name());
                httpURLConnection.connect();
                break;
            case PUT:
            case POST:
                httpURLConnection.setRequestMethod(method.name());
                httpURLConnection.setDoInput(true);
                httpURLConnection.setDoOutput(true);
                httpURLConnection.connect();
                if(StringUtils.isNotBlank(this.params)) this.writer(this.params, httpURLConnection.getOutputStream()); //使用raw调用
                break;
        }
    }

    protected void initSSL(HttpsURLConnection httpsURLConnection) {
        try {
            SSLContext sc = SSLContext.getInstance("ssl");
            sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new SecureRandom());
            httpsURLConnection.setSSLSocketFactory(sc.getSocketFactory());
            httpsURLConnection.setHostnameVerifier(new TrustAnyHostnameVerifier());
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    protected void writer(String params, OutputStream outputStream){
        try (PrintWriter writer = new PrintWriter(outputStream, true)) {
            writer.print(params);
        }
    }

    protected String reader(InputStream inputStream) throws IOException {
        StringBuilder result = new StringBuilder();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))){
            in.lines().forEach(o-> result.append(o).append("\n"));
        }
        return result.toString();
    }

    public String send(RequestMethod... method) throws IOException {
        return this.sendRequest(method.length == 0? RequestMethod.GET:method[0]);
    }

    public void send(Consumer<InputStream> consumer, RequestMethod... method) throws IOException {
        this.sendRequest(consumer, method.length == 0? RequestMethod.GET:method[0]);
    }

    public void send(BiConsumer<HttpURLConnection, InputStream> consumer, RequestMethod... method) throws IOException {
        this.sendRequest(consumer, method.length == 0? RequestMethod.GET:method[0]);
    }

    public void addHeader(Consumer<Map<String, String>> consumer){
        consumer.accept(this.headers);
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public void setParams(String params) {
        this.params = params;
    }

    public void setTimeOut(int timeOut){
        this.timeOut = timeOut;
    }

}
